#ifndef __POSICIONBACKTRACKING_H__
#define __POSICIONBACKTRACKING_H__

#include <Math.h> 

#define NORTE    1
#define ESTE     2
#define SUR      3
#define OESTE    4
#define INVALIDO 0

class PosicionBackTracking{

	private:
		int fila;
		int columna;
		int movimiento;
	
	public:
		PosicionBackTracking(int fila, int columna){

			this->fila = fila;
			this->columna = columna;
		}

		PosicionBackTracking(PosicionBackTracking* pb){

			this->fila = pb->getFila();
			this->columna = pb->getColumna();
		}

		void setPosicion(PosicionBackTracking* pb){
			this->fila = pb->getFila();
			this->columna = pb->getColumna();
			this->movimiento = NORTE;
		}

		void setPosicion(int fila, int columna){

			this->fila = fila;
			this->columna = columna;
			this->movimiento = NORTE;
		}

		void setFila(int fila){

			this->fila =fila;
		}

		void setColumna(int columna){

			this->columna = columna;
		}

		int getFila(){

			return this->fila;
		}

		int getColumna(){

			return this->columna;
		}

		int getMovimiento(){

			return this->movimiento;
		}

		void setMovimiento(int movimiento){

			this->movimiento = movimiento;
		}

		bool moverNorte(int fila, int columna){
			return (this->fila != 0);
		}

		bool moverEste(int fila, int columna){
			return (this->columna < (columna-1));
		}

		bool moverSur(int fila, int columna){
			return (this->fila < (fila-1));
		}

		bool moverOeste(int fila, int columna){

			return (this->columna != 0);
		}

		void setPrimerMovimiento(int filas, int columnas){

			if(this->moverNorte(filas,columnas)){
				this->setMovimiento(NORTE);
			}else if(this->moverEste(filas,columnas)){
				this->setMovimiento(ESTE);
			}else if(this->moverSur(filas,columnas)){
				this->setMovimiento(SUR);
			}else if(this->moverOeste(filas,columnas)){
				this->setMovimiento(OESTE);
			}
			
		}
		
		bool equals(PosicionBackTracking* otraPosicion){
			return ((this->fila == otraPosicion->getFila()) && (this->columna == otraPosicion->getColumna()));
		}

		float getDistancia(PosicionBackTracking *otroPunto){
			
			short int despX = abs(this->getColumna() - otroPunto->getColumna());
			short int despY = abs(this->getFila() - otroPunto->getFila());
			float dist = (float)(despX*despX + despY*despY);
			dist = sqrt(dist);
			return dist;
		}

		PosicionBackTracking* siguientePosicion(int* filas, int* columnas){
			
			PosicionBackTracking* siguiente = new PosicionBackTracking(0,0);
			
			/*
			 * En las siguientes sentecias se chequea que la posicion
			 * siguiente sea la valida para el recorrido, no dejando
			 * que esta caiga fuera del tablero y siga el orden estipulado
			 * de movimiento.
			 */
			switch (this->movimiento){

				case NORTE:
					if(this->moverNorte(*filas,*columnas)){
						siguiente->setPosicion( this->fila - 1, this->columna);
						if(this->moverEste(*filas,*columnas)){
							this->setMovimiento(ESTE);
						}else{
							if(this->moverSur(*filas,*columnas)){
								this->setMovimiento(SUR);
							}else{
								if(this->moverOeste(*filas,*columnas))
									this->setMovimiento(OESTE);
							}
						}
						break;
					}
				case ESTE:
					if(this->moverEste(*filas,*columnas)){
						siguiente->setPosicion(this->fila,this->columna+1);
						if(this->moverSur(*filas,*columnas)){
							this->setMovimiento(SUR);
						}else{
							if(this->moverOeste(*filas,*columnas)){
								this->setMovimiento(OESTE);
							}else{
								this->setMovimiento(INVALIDO);
							}
						}
						break;
					}
				case SUR:
					if(this->moverSur(*filas,*columnas)){
						siguiente->setPosicion(this->fila+1,this->columna);
						if(this->moverOeste(*filas,*columnas)){
							this->setMovimiento(OESTE);
						}else{
							this->setMovimiento(INVALIDO);
						}

						break;
					}
				case OESTE:
					if(this->moverOeste(*filas,*columnas)){
						siguiente->setPosicion(this->fila ,this->columna-1);
						this->setMovimiento(INVALIDO);
						break;
					}
			}
			
			return siguiente;
		}

		PosicionBackTracking* siguientePosicionAlternativa(int* filas, int* columnas){
			
			PosicionBackTracking* siguiente = new PosicionBackTracking(0,0);
			
			/*
			 * En las siguientes sentecias se chequea que la posicion
			 * siguiente sea la valida para el recorrido, no dejando
			 * que esta caiga fuera del tablero y siga el orden estipulado
			 * de movimiento.
			 */
			switch (this->movimiento){

				case NORTE:
					if(this->moverNorte(*filas,*columnas)){
						siguiente->setPosicion( this->fila - 1, this->columna);
						if(this->moverOeste(*filas,*columnas)){
									this->setMovimiento(OESTE);
						}else{
							if(this->moverSur(*filas,*columnas)){
								this->setMovimiento(SUR);
							}else{
								if(this->moverEste(*filas,*columnas))
									this->setMovimiento(ESTE);
							}
						}
						break;
					}
				case ESTE:
					if(this->moverEste(*filas,*columnas)){
						siguiente->setPosicion(this->fila,this->columna+1);
						if(this->moverSur(*filas,*columnas)){
							this->setMovimiento(SUR);
						}else{
							if(this->moverOeste(*filas,*columnas)){
								this->setMovimiento(OESTE);
							}else{
								this->setMovimiento(INVALIDO);
							}
						}
						break;
					}
				case SUR:
					if(this->moverSur(*filas,*columnas)){
						siguiente->setPosicion(this->fila+1,this->columna);
						if(this->moverOeste(*filas,*columnas)){
							this->setMovimiento(OESTE);
						}else{
							this->setMovimiento(INVALIDO);
						}

						break;
					}
				case OESTE:
					if(this->moverOeste(*filas,*columnas)){
						siguiente->setPosicion(this->fila ,this->columna-1);
						this->setMovimiento(INVALIDO);
						break;
					}
			}
			
			return siguiente;
		}
		
};

#endif